#include <iostream>
#include <string.h>

#if 0
// 函数模板
template <class T>
T Add(const T& a, const T& b) {
    return a + b;
}

int main() {
    std::cout << Add(1, 2) << std::endl;
    std::cout << Add<double>(1.1, 2) << std::endl;
    return 0;
}
#endif

// 类模板
template <class T>
class Stack
{
private:
    T* _array = nullptr;
    int _size = 0;
    int _capacity = 0;
public:
    Stack(int size=4)
        :_array(new T[size])
        ,_size(0)
        ,_capacity(size)
    {}

    ~Stack()
    {
        std::cout << "~Stack()" << std::endl; 
        delete [] _array;
        _array = nullptr;
        _size = _capacity = 0 ;
    }

    void Push(const T& x);

    void Print();
};

// 声明和定义分离时, 需额外定义模板, 且只能适配一次
// 类模板的声明定义分离不能分开两个文件做, 否则会链接错误
template <class T>
void Stack<T>::Push(const T& x)
{
    if(_size == _capacity)
    {
        T* tmp = new T[_capacity*2];
        memcpy(tmp, _array, sizeof(T)*(unsigned int)_size);
        delete[] _array;
        _array = tmp;
    }
    _array[_size++] = x;
}

// 声明和定义分离时, 需额外定义模板, 且只能适配一次
// 类模板的声明定义分离不能分开两个文件做, 否则会链接错误
template <class T>
void Stack<T>::Print()
{   
    for(int i=0;i<_size;++i)
    {
        std::cout << _array[i] << "->" ;
    }
    std::cout << std::endl;
}


int main()
{
    // 类模板必须显示声明数据类型
    Stack<int> st;
    st.Push(1);
    st.Push(2);
    st.Push(3);
    st.Push(4);
    st.Push(5);
    st.Push(7);
    st.Push(9);
    st.Print();

    Stack<double> st1;
    st1.Push(1.2);
    st1.Push(2.1);
    st1.Push(3);
    st1.Push(4);
    st1.Push(5.6);
    st1.Push(7);
    st1.Push(9);
    st1.Print();

    return 0;
}